﻿@using Resource;
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    <meta http-equiv="Expires" content="0">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-control" content="no-cache">
    <meta http-equiv="Cache" content="no-cache">
    @{ await Html.RenderPartialAsync("/Views/Shared/_LayoutScript.cshtml"); }
    @{ await Html.RenderPartialAsync("/Views/Shared/_StyleCss.cshtml"); }

    <script src="/lib/xlsx/xlsx.full.min.js?v=@DateTime.Now.Ticks"></script>
    <link href="/css/FailureModeBoxplot.css?v=@DateTime.Now.Ticks" rel="stylesheet" />
    <title>FailureModeBoxplot</title>
    <style type="text/css">
        /*报表样式*/
        html, body {
            background: url(../images/ProcessCapacity/bgwhite.png) no-repeat;
            background-size: cover;
            font-size: .16rem;
            color: #ffffff;
            position: relative;
            width: 100%;
            height: 100%;
            font-family: myFirstFont !important;
            color: black;
        }

        .hover-image {
            display: none;
            position: absolute;
            top: 20px;
            left: 0;
            width: 35vw;
            border: 1px solid #ccc;
            background: #fff;
            z-index: 999;
        }

        .warn-flag:hover .hover-image {
            display: block;
        }

        /*报表放大*/
        #maximizedreport {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            margin: 0;
            z-index: 1000;
            transition: all 0.3s;
            font-size: 1.5em !important;
            background-color: #f5f5f5;
        }

        #maximizedreport .note {
            font-size: 0.85em !important;
        }

        #maximizedreport #Tab1 {
            height: 90vh;
        }

        #maximizedreport #board #startdate,
        #maximizedreport #board #enddate {
            font-size: 0.85em !important;
            width: 12.5vw;
        }

        #maximizedreport #board select,
        #maximizedreport #board button,
        #maximizedreport #board .titleinput,
        #maximizedreport #dateto select
        #maximizedreport #dateno select {
            font-size: 0.85em !important;
            width: 9vw;
        }

        #maximizedreport #chart-container {
            height: 90vh;
            font-size: 0.85em !important;
        }

        #maximizedreport #chart-container th {
            font-size: 1.45em !important;
        }

        #maximizedreport .popup {
            width: 80%;
        }

        #maximizedreport .popup span,
        #maximizedreport #report td {
            font-size: 0.85em !important;
        }

        #maximizedreport #report th {
            font-size: 1.5em !important;
        }

        .rightTop {
            background-color: #f7fdff;
        }

        .dropbtn, button {
            background-color: #0aa9cd;
        }

        #query > button {
            background-color: #0aa9cd;
            border: 2px solid #0aa9cd;
        }

        .dropdown-content {
            background-color: #12bed0;
        }

        .Zebra {
            background-color: #e5ecff;
        }

        .ZebraNo {
            background-color: #e8f1f9;
        }

        .ZebraTo {
            background-color: #ffffff;
        }

        .warn {
            background-color: #ffcccc;
        }

        .note {
            color: red;
            font-size: 0.15rem;
            font-weight: bolder;
        }

        .warning {
            background-color: #ffaf0078;
            border-color: transparent;
        }

        .danger {
            background-color: #ff1f0078;
            border-color: transparent;
        }

        .jobnum:hover {
            background-color: #b3f1fe;
        }

        .truncate {
            /* max-width: 1.2rem; */
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            border-color: transparent;
        }

        td.percentage {
            border-color: transparent;
        }
        /*END*/

        #Tab1 {
            /* border: 1px solid #59ebe8; */
            height: 9.6rem;
            background-image: url('../images/loading.gif');
            background-size: 0.8rem 0.8rem;
            background-repeat: no-repeat;
            background-position: center;
        }

        .popup {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 80%;
            background-color: white;
            box-shadow: 0 0 10px rgba(4, 193, 250,1);
            border-radius: 8px;
            z-index: 7;
        }

        #yield_tbody {
            border-collapse: collapse;
        }

        #yield_tbody tr,
        #yield_tbody td {
            border: 1px solid gray;
        }

        .switch-container {
            display: flex;
            align-items: center;
        }

        .switch {
            position: relative;
            display: inline-block;
            width: 0.42rem;
            height: 0.24rem;
            top: 0.1rem;
        }

        .switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }

        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: 0.4s;
            border-radius: 0.5rem;
        }

        .slider:before {
            position: absolute;
            content: "";
            height: 0.18rem;
            width: 0.18rem;
            left: 0.03rem;
            bottom: 0.028rem;
            background-color: white;
            transition: 0.4s;
            border-radius: 50%;
        }

        input:checked + .slider {
            background-color: #4caf50;
        }

        input:checked + .slider:before {
            transform: translateX(0.18rem);
        }

        #toggle-outliers{
            width: 0.7rem;
            background-color: #ff9b00;
            border: 1px solid #ff9b00;
        }

        #toggle-outliers:hover {
            background-color: #ff6c00;
            border: 1px solid #ff6c00;
        }
        
    </style>
</head>
<body class="fill-parent" style="overflow-y: hidden; color: black;">
    <div class="main">
        <div class="header">
            <div class="header-left fl">
                <img src="/images/logo.png?v=@DateTime.Now.Ticks" class="scaled-image" draggable="false" oncontextmenu="return false;" ondragstart="return false;" />
            </div>
            <div class="btn">
                <spn>
                    <div id="query">
                        <div class="dropdown">
                            <button class="dropbtn">@Label.Desktop</button>
                            <div class="dropdown-content">
                                <a class="menudropdown" href=@Html.Raw($"https://dashboard.li.lumentuminc.net/API/DesktopApp/Dashboard.exe?v={DateTime.Now.Ticks}") download>@Label.Local</a>
                                <a class="menudropdown" href=@Html.Raw($"https://dashboard.li.lumentuminc.net/API/DesktopApp/Dashboard_lnk.zip?v={DateTime.Now.Ticks}") download>@Label.Shortcut</a>
                            </div>
                        </div>
                        <div class="dropdown">
                            <button class="dropbtn">@Label.Language</button>
                            <div class="dropdown-content">
                                <a class="menudropdown" onclick="setLanguageCookie('@Const.CNLANGUAGE')">@Label.Chinese</a>
                                <a class="menudropdown" onclick="setLanguageCookie('@Const.USLANGUAGE')">@Label.English</a>
                            </div>
                        </div>
                        <button class="modalBtn dimension">@Label.Full</button>
                    </div>
                </spn>
            </div>
            <div class="header-center fl">
                <div class="header-title"></div>
                <div class="header-img"></div>
            </div>
            <div class="header-right fl" id="time"></div>
            <div class="header-bottom fl"></div>
        </div>
        <div class="center">
            <div class="center-left fl">
                <div class="left-top rightTop border" id="report_id" ondblclick="maximizedreport()">
                    <div class="title note">
                        <span class="warn-flag" style="color:red; position: relative;">ℹ️<img src="../images/BoxChart.png?v=@DateTime.Now.Ticks" class="hover-image" /></span>
                        @Label.Note_FailureModeTrend
                    </div>
                    <div id="board" class="chart">
                        <div class="query">
                            <span class="titleinput tle">Site:</span>
                            <select id="cmb_site" name="Site" placeholder="select Site">
                                <option value="DG">@Label.DG</option>
                                <option value="AMT">@Label.AMT</option>
                            </select>
                            <select id="cmb_type" placeholder="select Type">
                                <option value="Daily">Daily</option>
                                <option value="Weekly">Weekly</option>
                                @*
                                <option value="Monthly">Monthly</option>
                                <option value="Yearly">Yearly</option>
                                <option value="CQ">Quarterly(CQ)</option>
                                <option value="FQ">Quarterly(FQ)</option>
                                *@
                            </select>
                            <span id="dateno">
                                <span class="titleinput tle">@Label.Time:</span>
                                <input type="date" id="startdate" name="startdate" placeholder="@Label.Start@Label.Time" />
                                <span class="titleinput tle">@Label.To</span>
                                <input type="date" id="enddate" name="enddate" placeholder="@Label.Start@Label.End" style="margin-right: 0.2rem;" />
                            </span>
                            <span id="dateto">
                                <span class="titleinput tle">@Label.Time:</span>
                                <select id="startyear" placeholder="select date"></select>
                                <select id="startto"></select>
                                <span class="titleinput tle">@Label.To</span>
                                <select id="endyear" placeholder="select date"></select>
                                <select id="endto" style="margin-right: 0.2rem;"></select>
                            </span>
                            <select id="cmb_projcode" placeholder="select ProjCode"></select>
                            <select id="cmb_process" placeholder="select Process" ></select>
                            <span class="titleinput tle">Grade:</span>
                            <select id="cmb_grade" placeholder="select Grade"></select>
                            <span class="titleinput tle">Item:</span>
                            <select id="cmb_testsitem" placeholder="select TestsItem"></select>
                            <span class="titleinput tle">Tester:</span>
                            <select id="cmb_tester" placeholder="select Tester"></select>
                            <button id="btn_query" class="btn btn-primary  btn-sm col-md-12" type="button" onclick="Getdata()">@Label.Query</button>
                            <button id="toggle-outliers">显示异常</button>
                        </div>
                        <div id="Tab1">
                            <div id="chart-container">
                                <div id="boxplot-chart"></div>
                            </div>
                            <div class="popup">
                                <span class="report_close" style="font-size:0.18rem;color:red; float:right;font-weight:bold;" onclick="funclose()">关闭×</span>
                                <div style="height:0.3rem">
                                    <span class="popup-title" style="font-size:0.15rem;color:#007bff;font-weight:bold;line-height:0.3rem;padding-left: 0.15rem;"></span>
                                </div>
                                <div id="report"></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script type="text/javascript" href="?v=@DateTime.Now.Ticks">
        $(".popup").css("display", "none");
        $(document).ready(function () {
            var whei = $(window).height();
            $("html").css({ fontSize: whei / 12.5 });
            $(window).resize(function () {
                if ($(".dimension").text() == "@Html.Raw(Label.Full)") {
                    var whei = $(window).height();
                    $("html").css({ fontSize: whei / 12.5 });
                }
                else {
                    var whei = $(window).width();
                    $("html").css({ fontSize: whei / 22 })
                }
            });

            function numberToUpperCase(number) {
                var uppercaseMonths = [
                    '一月', '二月', '三月', '四月', '五月', '六月',
                    '七月', '八月', '九月', '十月', '十一月', '十二月'
                ];
                return uppercaseMonths[number - 1];
            }
            var myDate = new Date();
            var result = numberToUpperCase(myDate.getMonth() + 1);
            $('.header-title').html("@Html.Raw(Label.Board_FailureModeTrend)");
            function getTime() {
                var myDate = new Date();
                var myYear = myDate.getFullYear();
                var myMonth = myDate.getMonth() + 1;
                var myToday = myDate.getDate();
                var myDay = myDate.getDay();
                var myHour = myDate.getHours();
                var myMinute = myDate.getMinutes();
                var mySecond = myDate.getSeconds();
                var week = ['@Label.Sunday', '@Label.Monday', '@Label.Tuesday', '@Label.Wednesday', '@Label.Thursday', '@Label.Friday', '@Label.Saturday'];
                var nowTime;

                nowTime = myYear + '-' + fillZero(myMonth) + '-' + fillZero(myToday) + '&nbsp;&nbsp;' + fillZero(myHour) + ':' + fillZero(myMinute) + ':' + fillZero(mySecond) + '&nbsp;&nbsp;' + week[myDay] + '&nbsp;&nbsp;';
                $('#time').html(nowTime);
            };

            function fillZero(str) {
                var realNum;
                if (str < 10) {
                    realNum = '0' + str;
                } else {
                    realNum = str;
                }
                return realNum;
            }
            setInterval(getTime, 1000);
            // 设置全屏
            $('.dimension').on('click', function (e) {
                var element = document.documentElement;
                 if ($(".dimension").text() == "@Html.Raw(Label.Full)") {
                    // 判断浏览器设备类型
                    if (element.requestFullscreen) {
                        element.requestFullscreen();
                    } else if (element.mozRequestFullScreen) {       //兼容火狐
                        element.mozRequestFullScreen();
                    } else if (element.webkitRequestFullscreen) {    //兼容谷歌
                        element.webkitRequestFullscreen();
                    } else if (element.msRequestFullscreen) {        //兼容IE
                        element.msRequestFullscreen();
                    }
                    $(".dimension").text("@Html.Raw(Label.Exit + Label.Full)");
                } else {
                    if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.mozCancelFullScreen) {
                        document.mozCancelFullScreen();
                    } else if (document.webkitCancelFullScreen) {
                        document.webkitCancelFullScreen();
                    } else if (document.msExitFullscreen) {
                        document.msExitFullscreen();
                    }
                    $(".dimension").text("@Html.Raw(Label.Full)");
                }
            });
            //$('#btn_query').prop('disabled', true);
        });

        //下拉框设置
        function getWeekNumber(date = new Date()) {
            //将周日(0)变成6，周一变成0
            const day = (date.getDay() + 6) % 7;
            const monday = new Date(date);
            monday.setDate(date.getDate() - day);
            const yearStart = new Date(date.getFullYear(), 0, 1);
            const yearStartDay = (yearStart.getDay() + 6) % 7;
            const firstMonday = new Date(yearStart);
            firstMonday.setDate(yearStart.getDate() - yearStartDay);
            const diff = monday - firstMonday;
            const week = Math.ceil(diff / (7 * 24 * 60 * 60 * 1000));
            return String(week).padStart(2, '0');
        };
        var Datesetting = function() {
            $("#startdate, #enddate, #startyear, #startto, #endyear, #endto").css({
                "height": "0.36rem",
                "transform": "translateY(0.02rem)"
            });
            var type = $("#cmb_type").val();
            function addOptions(selectId, options, checked) {
                var $select = $(selectId);
                $select.empty();
                options.forEach(function(option) {
                    $select.append(new Option(option.label, option.value));
                });
                if(checked != null)
                {
                    $select.val(checked);
                }
            }
            if (type == "Daily") {
                $("#dateno").show();
                $("#dateto").hide();
                $('#startdate').on('change', function () {
                    var startDate = new Date($(this).val());
                    var endDate = new Date($('#enddate').val());
                    startDate.setDate(startDate.getDate() + 1);
                    var minEndDate = startDate.toISOString().split('T')[0];
                    $('#enddate').attr('min', minEndDate);
                    if (endDate < startDate) {
                        $('#enddate').val($(this).val());
                    }
                });
                $('#enddate').on('change', function () {
                    var startDate = new Date($('#startdate').val());
                    var endDate = new Date($(this).val());
                    endDate.setDate(endDate.getDate() - 1);
                    var maxStartDate = endDate.toISOString().split('T')[0];
                    $('#startdate').attr('max', maxStartDate);
                    if (startDate > endDate) {
                        $('#startdate').val($(this).val());
                    }
                });

            } else {
                $("#dateto").show();
                $("#dateno").hide();
                var currentYear = new Date().getFullYear();
                var previousYear = currentYear - 1;
                addOptions('#startyear, #endyear', [{ label: previousYear, value: previousYear },{ label: currentYear, value: currentYear }]);
                if (type == "Yearly") {
                    $("#endto, #startto").hide();
                } else {
                    $("#endto, #startto").show();
                    var checked = null;
                    var options = [];
                    if (type == "Weekly") {
                        for (var week = 1; week <= 52; week++) {
                            options.push({ label: `Week` + String(week).padStart(2, "0"), value: String(week).padStart(2, "0") });
                        }
                        checked = getWeekNumber();
                    }
                    else if (type == "Monthly") {
                        for (var month = 1; month <= 12; month++) {
                            options.push({ label: "Month" + String(month).padStart(2, "0"), value: String(month).padStart(2, "0") });
                        }
                    }
                    else if (type == "CQ") {
                        for (var quarter = 1; quarter <= 4; quarter++) {
                            options.push({ label: "CQ" + quarter, value: "CQ" + quarter });
                        }
                    }
                    else if (type == "FQ") {
                        for (var quarter = 1; quarter <= 4; quarter++) {
                            options.push({ label: "FQ" + quarter, value: "FQ" + quarter });
                        }
                    }
                    addOptions('#startto, #endto', options,checked);
                }
            }
        }

        //验证
        var validate = function () {
            var startdate, enddate;
            var type = $("#cmb_type").val();
            function validateDateRange(startdate, enddate) {
                if (startdate > enddate) {
                    alert("时间范围有误！");
                    return;
                }
            }
            if (type == "Daily") {
                startdate = $('#startdate').val();
                enddate = $('#enddate').val();
            }
            if (["Weekly", "Monthly", "CQ", "FQ"].includes(type)) {
                startdate = parseInt($("#startyear").val() + $("#startto").val());
                enddate = parseInt($("#endyear").val() + $("#endto").val());
                validateDateRange(startdate, enddate);
            }
            if (type == "Yearly") {
                startdate = parseInt($("#startyear").val());
                enddate = parseInt($("#endyear").val());
                validateDateRange(startdate, enddate);
            }

            if (["CQ", "FQ"].includes(type)) {
                startdate = `${$("#startto").val()}_${$("#startyear").val().slice(-2)}`;
                enddate = `${$("#endto").val()}_${$("#endyear").val().slice(-2)}`;
            }
            return {
                startdate: startdate.toString().replace(/-/g, ''),
                enddate: enddate.toString().replace(/-/g, '')
            };
        }

        $('#cmb_type').on('change', function() {
            Datesetting();
            $("#endyear").val($("#startyear option:last").val());
        });

        $("#dateto select").on("change", function () {
            validate();
        });

        var ComboxAction = function () {
            $('#cmb_type').val('Daily').trigger('change');
            var params = {};
            var header_key = {};
            function loadSelect(url,targetSelect,type,callback) {
                var dates = validate();
                header_key.site = $("#cmb_site").val();
                header_key.type = $("#cmb_type").val();
                header_key.start = dates.startdate;
                header_key.end = dates.enddate;
                params.header_key = JSON.stringify(header_key);
                $.ajax({
                    url: api + url,
                    type: 'POST',
                    data: params,
                    success: function(data) {
                        var select = $(targetSelect);
                        if (type) {
                            select.empty().append('<option value="ALL">ALL</option>');
                        } else {
                            select.empty();
                        }
                        $.each(data.ReturnData, function(_, item) {
                            select.append('<option value="' + item.VALUE + '">' + item.TEXT + '</option>');
                        });
                        if (typeof callback === 'function') {
                            callback();
                        }
                    }
                });
            }

            //ProjCode
            $('#cmb_site').change(function() {
                loadSelect('/ReportAction/GetComboxFailureBoxplotProjCode', '#cmb_projcode', false, function () {
                    $("#cmb_projcode").val("NCCSAD").trigger("change");
                })
            });
            
            //$("#cmb_site").val("DG").trigger("change");
            $("#cmb_site").prop('selectedIndex', 0).trigger('change');

            //Process
            $('#cmb_projcode').change(function() {
                var projCode = $(this).val();
                if (projCode !== 'ALL') {
                    params.proj_code = projCode;
                    loadSelect('/ReportAction/GetComboxFailureBoxplotProcess', '#cmb_process', false, function () {
                        $("#cmb_process").prop('selectedIndex', 1).trigger('change');
                        //$("#cmb_process").val("FT").trigger("change");
                    });
                }
            });

            //grade
            $('#cmb_process').change(function() {
                var projCode = $('#cmb_projcode').val();
                var process = $(this).val();
                if (projCode !== 'ALL' && process !== 'ALL') {
                    params.proj_code = projCode;
                    params.process_id = process;
                    loadSelect('/ReportAction/GetComboxFailureBoxplotGrade', '#cmb_grade', false, function () {
                        $("#cmb_grade").prop('selectedIndex', 0).trigger('change');
                    });
                }
            });

            //TestsItem
            $('#cmb_grade').change(function() {
                var projCode = $('#cmb_projcode').val();
                var process = $('#cmb_process').val();
                var grade = $(this).val();
                if (projCode !== 'ALL' && process !== 'ALL') {
                    params.proj_code = projCode;
                    params.process_id = process;
                    header_key.grade = grade;
                    loadSelect('/ReportAction/GetComboxFailureBoxplotTestItem', '#cmb_testsitem', false, function () {
                        $("#cmb_testsitem").prop('selectedIndex', 0).trigger('change');
                    });
                }
            });

            //Tester
            $('#cmb_testsitem').change(function() {
                var projCode = $('#cmb_projcode').val();
                var process = $('#cmb_process').val();
                var grade = $('#cmb_grade').val();
                var testsItem = $(this).val();
                if (projCode !== 'ALL' && process !== 'ALL' && testsItem !== 'ALL') {
                    params.proj_code = projCode;
                    params.process_id = process;
                    header_key.grade = grade;
                    header_key.testitem = testsItem;
                    loadSelect('/ReportAction/GetComboxFailureBoxplotTester', '#cmb_tester', true, function () {
                        $("#cmb_tester").prop('selectedIndex', 0).trigger('change');
                    });
                }
            });

            $('#cmb_tester').change(function() {
                getdate();
            })
        };

        //图表自适应大小
        const chartsMap = new Map();
        const chartIds = ['boxplot-chart'];
        function echartsautomatic() {
            chartIds.forEach(chartId => {
                const el = document.getElementById(chartId);
                if (el) {
                    chartsMap.set(chartId, echarts.init(el));
                }
            });
            window.onresize = function () {
                chartsMap.forEach(function (chart) {
                    chart.resize();
                });
            };
            window.addEventListener("resize", resizeCharts);
        }
        function resizeCharts() {
            chartsMap.forEach(chart => chart.resize());
        }
        const observer = new ResizeObserver(resizeCharts);

        //定时查询
        var Tabtimer;
        function TabInterval() {
            clearInterval(Tabtimer);
            //每隔10m执行一次
            Tabtimer = setInterval(function () {
                var endDate = new Date($("#enddate").val());
                if (endDate > new Date()) {
                    getdate();
                }
            }, 10 * 60 * 1000);
        }

        $(function () {
            var startDate = new Date();
            startDate.setMonth(startDate.getMonth() - 1);
            startDate.setHours(0, 0, 0, 0);
            var endDate = new Date();
            endDate.setHours(0, 0, 0, 0);
            $('#startdate').val(startDate.toISOString().split('T')[0]);
            $('#enddate').val(endDate.toISOString().split('T')[0]);
            ComboxAction();
            // setTimeout(function () {
            //     Getdata();
            // }, 1800);
        })

        var Getdata = function () {
            getdate();
            TabInterval();
        }

        //报表导出
        var exportDdata = function(type){
            const book = XLSX.utils.book_new();
            const sheet = XLSX.utils.json_to_sheet(Tab.report);
            XLSX.utils.book_append_sheet(book, sheet);
            XLSX.writeFile(book,`${type}.xlsx`);
        }

        function loadingshow() {
            $('#btn_query').prop('disabled', true);
            $('#Tab1').css('background-image', 'url("../images/loading.gif")');
            $('#Tab1').css('background-size', '0.8rem 0.8rem');
            $('#Tab1').css('background-repeat', 'no-repeat');
            $('#Tab1').css('background-position', 'center');
        }
        function loadingnone() {
            $('#btn_query').prop('disabled', false);
            $('#Tab1').css('background-image', 'none');
        }
        function getExcelColor(percentage) {
            let red, green;
            if (percentage <= 65) {
                red = 255;
                green = Math.round((percentage / 65) * 255);
            } else if (percentage <= 90) {
                green = 255;
                red = Math.round(255 - ((percentage - 75) / 30) * 200);
            } else {
                green = Math.round(255 - ((percentage - 90) / 10) * 50);
                red = Math.round(55 - ((percentage - 90) / 10) * 25);
            }
            return `rgb(${red}, ${green}, 150)`;
        }

        //获取数据
        var Tab;
        var getdate = function () {
            var dates = validate();
            var header_key = {
                site: $("#cmb_site").val(),
                grade: $('#cmb_grade').val(),
                testitem:$("#cmb_testsitem").val(),
                tester:$("#cmb_tester").val(),
                start: dates.startdate,
                end:dates.enddate
            };
            var pam = {};
            pam.proj_code = $('#cmb_projcode').val();
            pam.process_id = $('#cmb_process').val();
            pam.type = $("#cmb_type").val();
            pam.header_key = JSON.stringify(header_key);
            loadingshow();
            $.ajax({
                type: "POST",
                url: api + "/ReportAction/GetTestitemBoxplot",
                data: pam,
                dataType: "json",
                async: true,
                success: function (dt) {
                    loadingnone();
                    Tab = dt.ReturnData;
                    if(Tab.length > 0){
                        boxplotChart(Tab);
                    }
                    //console.log(JSON.stringify(Tab));
                }
            });
        }

        function boxplotChart(Tab) {
            const rawData = Tab;
            const testDates = rawData.map(item => item.TEST_DATE);
            //1提取所有Q1、Q3
            const allQ1 = rawData.map(item => parseFloat(item.Q1));
            const allQ3 = rawData.map(item => parseFloat(item.Q3));

            //百分位函数：计算指定百分位数(四分位数)
            function percentile(arr, p) {
                const sorted = arr.slice().sort((a, b) => a - b);
                const index = (sorted.length - 1) * p;
                const lower = Math.floor(index);
                const upper = Math.ceil(index);
                const weight = index - lower;
                return sorted[lower] * (1 - weight) + sorted[upper] * weight;
            }

            //2计算全局 Q1(25%)和 Q3(75%) 再求IQR
            const globalQ1 = percentile(allQ1, 0.25);
            const globalQ3 = percentile(allQ3, 0.75);
            const globalIQR = globalQ3 - globalQ1;

            //3计算异常判断上下限
            const lowerBound = globalQ1 - 2 * globalIQR;
            const upperBound = globalQ3 + 2 * globalIQR;

            //4全局异常标记 min/max 超出上下限就是异常箱子
            rawData.forEach(item => {
                const minVal = parseFloat(item.MIN_VAL);
                const maxVal = parseFloat(item.MAX_VAL);
                /* 单独判读每一个箱子
                const q1 = parseFloat(item.Q1);
                const q3 = parseFloat(item.Q3);
                const IQR = q3 - q1;
                const lowerBound = q1 - 1.5 * IQR;
                const upperBound = q3 + 1.5 * IQR;
                */
                //标记异常
                item._isAbnormal = !(minVal >= lowerBound && maxVal <= upperBound);
            });

            let showOutliers = false;
            function getCommonOption() {
                const isBER = $("#cmb_testsitem").val().includes("BER");
                const yAxisType = isBER ? 'log' : 'value';

                const filteredData = rawData.filter(item => showOutliers || !item._isAbnormal);
                const boxDataWithStyle = filteredData.map(item => {
                    const box = [
                        parseFloat(item.MIN_VAL) || 1e-10,
                        parseFloat(item.Q1) || 1e-10,
                        parseFloat(item.MEDIAN) || 1e-10,
                        parseFloat(item.Q3) || 1e-10,
                        parseFloat(item.MAX_VAL) || 1e-10
                    ];
                    const isAbnormal = item._isAbnormal;
                    return {
                        value: box,
                        itemStyle: {
                            color: isAbnormal ? 'rgba(255, 69, 0, 0.4)' : 'rgba(100, 149, 237, 0.8)',
                            borderColor: isAbnormal ? '#FF4500' : '#4169E1',
                            borderWidth: 1.5
                        }
                    };
                });

                const medianLine = filteredData.map(item => parseFloat(item.MEDIAN));
                const filteredTesters = filteredData.map(item => item.TESTER);
                return {
                    tooltip: {
                        trigger: 'axis',
                        axisPointer: { type: 'cross' }
                    },
                    toolbox: {
                        feature: {
                            saveAsImage: {
                                show: true,
                                name: 'FailureModeBoxplot_Chart',
                                type: 'png',              
                                backgroundColor: '#fff', 
                                pixelRatio: 2 
                            }
                        }
                    },
                    legend: {
                        data: [rawData[0].HEADER_KEY, 'Median Line']
                    },
                    grid: {
                        top: '10%',
                        right: '5%',
                        left: '4%',
                        width: '92%',
                        bottom: '40%'
                    },
                    xAxis: [
                        {
                            type: 'category',
                            data: filteredTesters,
                            position: 'bottom',
                            name: 'Testers',
                            offset: 15,
                            axisTick: { inside: false },
                            axisLine: {
                                show: true,
                                onZero: false,
                                lineStyle: { color: '#333' }
                            },
                            splitLine: {
                                show: true,
                                lineStyle: { type: 'dashed' }
                            },
                            axisLabel: {
                                interval: filteredTesters.length >= 115 ? Math.ceil(filteredTesters.length / 115) : 0,
                                formatter: function (value) {
                                    return value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase().split('').join('\n');
                                },
                                textStyle: { fontSize: '0.15rem' }
                            }
                        },
                        {
                            type: 'category',
                            data: testDates,
                            position: 'bottom',
                            name: 'Date',
                            offset: 180,
                            axisPointer: { show: true },
                            axisLine: {
                                show: true,
                                onZero: false,
                                lineStyle: { color: '#333' }
                            },
                            axisLabel: {
                                interval: testDates.length >= 24 ? Math.ceil(testDates.length / 24) : 0,
                                textStyle: { fontSize: '0.16rem' }
                            }
                        }
                    ],
                    yAxis: {
                        name: 'Value',
                        type: yAxisType,
                        logBase: yAxisType === 'log' ? 10 : undefined,
                        scale: true,
                        axisLabel: {
                            formatter: function (value) {
                                if (Math.abs(value) >= 1e6 || (Math.abs(value) > 0 && Math.abs(value) <= 1e-4) || isBER) {
                                    return value.toExponential();
                                } else {
                                    return value.toLocaleString();
                                }
                            }
                        },
                        axisLine: { onZero: false },
                        splitLine: {
                            show: true,
                            lineStyle: { type: 'dashed' }
                        }
                    },
                    dataZoom: [
                        {
                            type: 'inside',
                            start: 0,
                            end: 100,
                            xAxisIndex: [0, 1],
                        },
                        {
                            type: 'slider',
                            start: 0,
                            end: 100,
                            xAxisIndex: [0, 1],
                            handleSize: 0
                        }
                    ],
                    series: [
                        {
                            name: rawData[0].HEADER_KEY,
                            type: 'boxplot',
                            data: boxDataWithStyle,
                            xAxisIndex: 0,
                            emphasis: {
                                itemStyle: {
                                    borderColor: '#FF4500'
                                }
                            },
                            markLine: {
                                silent: false,
                                symbol: ['none', 'none'],
                                lineStyle: {
                                    type: 'dashed',
                                    width: 2
                                },
                                label: {
                                    formatter: '{b}\n{c}',
                                    backgroundColor: 'rgba(255,255,255,0.8)',
                                    color: '#333',
                                    borderRadius: 4,
                                    padding: [4, 8],
                                    position: 'end'
                                },
                                data: [
                                    {
                                        name: 'Min均值',
                                        yAxis: isBER ? rawData[0].AVG_MIN.toExponential() : rawData[0].AVG_MIN,
                                        lineStyle: { color: '#2ca02c' },
                                        label: { color: '#2ca02c',fontSize: 8 }
                                    },
                                    {
                                        name: 'Max均值',
                                        yAxis: isBER ? rawData[0].AVG_MAX.toExponential() : rawData[0].AVG_MAX,
                                        lineStyle: { color: '#ff7f0e' },
                                        label: { color: '#ff7f0e',fontSize: 8 }
                                    }
                                ]
                            }
                        },
                        {
                            name: 'Median Line',
                            type: 'line',
                            data: medianLine,
                            xAxisIndex: 0,
                            smooth: true,
                            lineStyle: { type: 'solid' },
                            symbol: 'circle',
                            symbolSize: filteredTesters.length > 100 ? 5 : 8,
                            itemStyle: { color: '#f1319f' }
                        }
                    ]
                };
            }

            const renderChart = () => {
                const option = getCommonOption();
                if (!window.myChart) {
                    window.myChart = echarts.init(document.getElementById('boxplot-chart'));
                    window.addEventListener('resize', () => window.myChart.resize());
                }
                window.myChart.setOption(option, true);
            };

            $('#toggle-outliers').off('click').on('click', function () {
                showOutliers = !showOutliers;
                $(this).text(showOutliers ? '隐藏异常' : '显示异常');
                renderChart();
            });

            renderChart(); 
        }

        function funclose() {
            $(".popup").css("display", "none");
        }

        //合并相同行
        function mergeFunc(tableId, maxCol) {
            var tab = document.getElementById(tableId);
            //var maxCol = 3;
            //maxcol用于设置需要合并的列数
            var count, start;
            for (var col = maxCol - 1; col >= 0; col--) {
                //用于存储相同个数
                count = 1;
                for (var i = 0; i < tab.rows.length; i++) {
                    if (i > 0 && col > 0 && tab.rows[i].cells[col].innerHTML == tab.rows[i - 1].cells[col].innerHTML
                        && tab.rows[i].cells[col - 1].innerHTML == tab.rows[i - 1].cells[col - 1].innerHTML) {
                        count++;
                    } else if (i > 0 && col == 0 && tab.rows[i].cells[col].innerHTML == tab.rows[i - 1].cells[col].innerHTML) {
                        count++;
                    } else {
                        if (count > 1) {
                            start = i - count;
                            tab.rows[start].cells[col].rowSpan = count;
                            for (var j = start + 1; j < i; j++) {
                                tab.rows[j].removeChild(tab.rows[j].cells[col]);
                            }
                            count = 1;
                        }
                    }
                }
                if (count > 1) {
                    start = i - count;
                    tab.rows[start].cells[col].rowSpan = count;
                    for (var j = start + 1; j < i; j++) {
                        tab.rows[j].removeChild(tab.rows[j].cells[col]);
                    }
                }
            }
        }

        //Report
        var reportDetail = function () {
            var product = $('#cmb_product_code').val();
            var process = $('#cmb_process').val();
            let filteredData = process === "ALL" && Tab.report || Tab.report.filter(item => item.STAGE === process);
            if(filteredData.length>0){
                $(".popup").css("display", "block");
                $(".popup-title").text(`${product}_${process}`);
                var data = filteredData.map(item => {
                    let newItem = Object.assign({}, item);
                    delete newItem.YEAR_NO;
                    return newItem;
                });
                $("#report").empty();
                var left_table_html = `
                <table id="myTable" class="DataSheet" border="1" style="width: 100%; height: 100%;">
                    <thead><tr></tr></thead>
                    <tbody id="yield_tbody"></tbody>
                </table>`;
                $("#report").append(left_table_html);
                var table = $('#myTable');
                var tbody = table.find('tbody');
                var headerRow = table.find('thead tr');
                var headers = Object.keys(data[0]);
                headers.forEach(function (header) {
                    headerRow.append('<th>' + header + '</th>');
                });
                data.forEach(function (row, index) {
                    index++;
                    let newRow = $(`<tr class="${(index % 2) ? "ZebraNo" : "ZebraTo"}"></tr>`);
                    headers.forEach(function (header, columnindex) {
                        if (["FAILURERATE", "FPY"].includes(header)) {
                            row[header] = (parseFloat(row[header]) * 100).toFixed(2) + '%';
                        }
                        newRow.append(`<td class="truncate">${row[header]}</td>`);
                    });
                    tbody.append(newRow);
                });
                if (data.length > 45) {
                    $("#report").css("height", "7rem");
                    $("#report").css("overflow-y", "auto");
                } else {
                    $("#report").css("height", "50%");
                }
                mergeFunc("myTable", 7);
            }
        }

        //区域放大
        var maximized = false;
        function toggleMaximize(elementId, maximizedId, chartId) {
            const tab = document.getElementById(elementId) || document.getElementById(maximizedId);
            if (tab) {
                if (tab.id === elementId) {
                    maximized = true;
                    tab.id = maximizedId;
                    if (chartId) maxchart(chartId);
                } else {
                    maximized = false;
                    tab.id = elementId;
                    if (chartId) minchart(chartId);
                }
            }
            observer.observe(document.getElementById("chart-container"));
        }
        function maximizedreport() {
            //toggleMaximize("report_id", "maximizedreport");
        }
    </script>
</body>
</html>
